import input from '../../stream/input.js'
import token from '../../stream/token.js'

const is = (tokens) => {
  return tokens.peek().type === 'identifier'
}

const parse = (tokens, name) => {
  const node = {
    type: 'CallExpression',
    callee: {
      type: 'Identifier',
      name: ''
    },
    arguments: [],
    alias: null
  }

  if (name) {
    node.callee.name = name
  } else {
    node.callee.name = tokens.peek().value
    tokens.next()
  }

  if (tokens.peek().type === 'dot' && tokens.peek().value === '.') {
    tokens.next()

    node.alias = node.callee.name

    if (tokens.peek().type === 'identifier') {
      node.callee.name = tokens.peek().value
    } else {
      tokens.croak(`Can't handle token: ${ tokens.peek().value }`)
    }

    tokens.next()
  }

  if (tokens.peek().type === 'punctuation' && tokens.peek().value === '(') {
    tokens.next()

    if (tokens.peek().type === 'punctuation' && tokens.peek().value === ')') {
      tokens.next()
      return node
    }

    while (!(tokens.peek().type === 'punctuation' && tokens.peek().value === ')')) {
      if (tokens.peek().type === 'identifier' || tokens.peek().type === 'literal' || tokens.peek().type === 'number') {
        const type = tokens.peek().type === 'identifier' ? 'Identifier' : 'Literal'

        node.arguments.push({
          type,
          value: tokens.peek().value
        })

        tokens.next()

        let alias = null
        if (tokens.peek().type === 'dot' && tokens.peek().value === '.') {
          tokens.next()

          if (tokens.peek().type === 'identifier') {
            alias = node.arguments[node.arguments.length - 1].value
            node.arguments[node.arguments.length - 1].value = tokens.peek().value
          } else {
            tokens.croak(`Can't handle token: ${ tokens.peek().value }`)
          }

          tokens.next()
        }

        if (tokens.peek().type === 'punctuation' && tokens.peek().value === '(') {
          const prevNode = node.arguments[node.arguments.length - 1]
          const temp_code = [ `${ (alias === null || alias === '') ? '' : `${ alias }.` }${ prevNode.value }`, '(' ]

          tokens.next()

          let count = 0

          while (!(tokens.peek().type === 'punctuation' && tokens.peek().value === ')') || count > 0) {
            const current = tokens.peek()

            if (current.type === 'punctuation' && current.value === '(') {
              count++
            }

            if (current.type === 'literal') {
              temp_code.push('"')
              temp_code.push(current.value)
              temp_code.push('"')
              tokens.next()
              continue
            }

            temp_code.push(current.value)
            tokens.next()

            if (current.type === 'punctuation' && current.value === ')') {
              count--
            }
          }

          temp_code.push(')')
          tokens.next()

          node.arguments.pop()
          node.arguments.push(parse(token(input(temp_code.join('')))))
        }

        if (tokens.peek().type === 'punctuation' && tokens.peek().value === ')') {
          tokens.next()
          break
        }

        if (tokens.peek().type === 'punctuation' && tokens.peek().value === ',') {
          tokens.next()
        } else {
          tokens.croak('Expecting "," after argument in call expression')
        }
      } else if (tokens.peek().type === 'punctuation' && tokens.peek().value === '(') {
        tokens.next()

        if (tokens.peek().type !== 'punctuation' || tokens.peek().value !== ')') {
          tokens.croak(`Can't handle token: ${ tokens.peek().value }`)
        }

        tokens.next()

        if (tokens.peek().type !== 'operator' || tokens.peek().value !== '->') {
          tokens.croak(`Can't handle token: ${ tokens.peek().value }`)
        }

        tokens.next()

        if (tokens.peek().type === 'punctuation' && tokens.peek().value === '{') {
          tokens.next()

          node.arguments.push({
            type: 'BlockStatement',
            body: []
          })

          let count = 0
          while (!(tokens.peek().type === 'punctuation' && tokens.peek().value === '}') || count > 0) {
            if (tokens.peek().type === 'punctuation' && tokens.peek().value === '{') {
              count++
            } else if (tokens.peek().type === 'punctuation' && tokens.peek().value === '}') {
              count--
            }
            node.arguments[node.arguments.length - 1].body.push(tokens.next())
          }

          tokens.next()

          if (tokens.peek().type === 'punctuation' && tokens.peek().value === ',') {
            tokens.next()
          } else if (tokens.peek().type === 'punctuation' && tokens.peek().value === ')') {
            tokens.next()
            break
          } else {
            tokens.croak('Expecting "," after argument in call expression')
          }
        } else {
          tokens.croak(`Can't handle token: ${ tokens.peek().value }`)
        }
      } else {
        tokens.croak('Expecting identifier, literal, number or callback in call expression')
      }
    }
  } else {
    tokens.croak('Expecting "(" after identifier in call expression')
  }

  return node
}

export default {
  is,
  parse
}
